ViewModel 源码分析

2023-09-05

假设存在 MainViewModel:

1
2
3
4
5
6
class MainViewModel : ViewModel() {

override fun onCleared() {
super.onCleared()
}
}

一般情况下,获取 ViewModel 的实例是通过如下代码:

1
2
3
4
5
6
7
8
9
class MainActivity : AppCompatActivity() {

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)

val vm = ViewModelProvider(this@MainActivity)[MainViewModel::class.java]
}
}

查看 ViewModelProvider 构造函数:

1
2
3
public constructor(
owner: ViewModelStoreOwner
) : this(owner.viewModelStore, defaultFactory(owner), defaultCreationExtras(owner))

通过传入的 ViewModelStoreOwner 获取其持有的 ViewModelStore 实例,由于 ComponentActivity 实现了 ViewModelStoreOwner 接口,所以 ComponentActivity 内部持有一个 ViewModelStore 实例,其赋值是在 ComponentActivity 的 ensureViewModelStore 方法中:

1
2
3
4
5
6
7
8
9
10
11
12
13
void ensureViewModelStore() {
if (mViewModelStore == null) {
NonConfigurationInstances nc =
(NonConfigurationInstances) getLastNonConfigurationInstance();
if (nc != null) {
// Restore the ViewModelStore from NonConfigurationInstances
mViewModelStore = nc.viewModelStore;
}
if (mViewModelStore == null) {
mViewModelStore = new ViewModelStore();
}
}
}

ViewModelStore 类很简单,内部持有一个 Map,用于存取 ViewModel,以及 clear。

再查看 ViewModelProvider 的 get 方法:

1
2
3
4
5
public open operator fun <T : ViewModel> get(modelClass: Class<T>): T {
val canonicalName = modelClass.canonicalName
?: throw IllegalArgumentException("Local and anonymous classes can not be ViewModels")
return get("$DEFAULT_KEY:$canonicalName", modelClass)
}

由于只提供了 modelClass,没有提供 key,所以会给该 ViewModel 分配一个根据其类名生成的默认的 key,根据此 key 去 ViewModelStore 中查找是否有该 ViewModel,如果没有的话,则根据 factory 生成一个 ViewModel 存入 ViewModelStore 并返回:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public open operator fun <T : ViewModel> get(key: String, modelClass: Class<T>): T {
val viewModel = store[key]
if (modelClass.isInstance(viewModel)) {
(factory as? OnRequeryFactory)?.onRequery(viewModel!!)
return viewModel as T
} else {
@Suppress("ControlFlowWithEmptyBody")
if (viewModel != null) {
// TODO: log a warning.
}
}
val extras = MutableCreationExtras(defaultCreationExtras)
extras[VIEW_MODEL_KEY] = key
// AGP has some desugaring issues associated with compileOnly dependencies so we need to
// fall back to the other create method to keep from crashing.
return try {
factory.create(modelClass, extras)
} catch (e: AbstractMethodError) {
factory.create(modelClass)
}.also { store.put(key, it) }
}

由于我们也没有提供 factory,所以这里的 facoty 是通过 defaultFactory 获取的默认的 factory,defaultFactory 是 AndroidViewModelFactory 伴生类中的方法,我们看下 defaultFactory 的获取流程:

1
2
3
internal fun defaultFactory(owner: ViewModelStoreOwner): Factory =
if (owner is HasDefaultViewModelProviderFactory)
owner.defaultViewModelProviderFactory else instance

如果传入的 ViewModelStoreOwner 是 HasDefaultViewModelProviderFactory 的实现类,那么 defaultFactory 就是 owner 的 defaultViewModelProviderFactory,否则 defaultFactory 就是 NewInstanceFactory 的实例:

1
2
3
4
5
6
7
8
9
@JvmStatic
public val instance: NewInstanceFactory
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
get() {
if (sInstance == null) {
sInstance = NewInstanceFactory()
}
return sInstance!!
}

由于 ComponentActivity 也实现了 HasDefaultViewModelProviderFactory 接口,所以这里的 defaultFactory 就是 ComponentActivity 所持有的 SavedStateViewModelFactory 实例:

1
2
3
4
5
6
7
8
9
public ViewModelProvider.Factory getDefaultViewModelProviderFactory() {
if (mDefaultFactory == null) {
mDefaultFactory = new SavedStateViewModelFactory(
getApplication(),
this,
getIntent() != null ? getIntent().getExtras() : null);
}
return mDefaultFactory;
}

P.S. ComponentActivity 和 Fragment 都实现了 HasDefaultViewModelProviderFactory 接口 ,并且他们内部持有的都是 SavedStateViewModelFactory 类型的 factory。

SavedStateViewModelFactory 的内部又持有一个 AndroidViewModelFactory 类型的 factory,如果 ViewModel 是 AndroidViewoModel,则使用 AndroidViewModelFactory 创建 ViewModel 实例,否则使用 NewInstanceFactory 创建无参 ViewModel。

内部提供的这些 Factory 都是通过反射创建 ViewModel 的实例,所以如果要创建带参数的 ViewModel,则需要自定义 Factory,在 create 方法中自行实例化 ViewModel。

那么当屏幕旋转导致 Activity 重建,ViewModel 是如何实现恢复数据的?

我们再来看一下 ComponentActivity 中 ViewModelStore 是如何创建的:

1
2
3
4
5
6
7
8
9
10
11
12
13
void ensureViewModelStore() {
if (mViewModelStore == null) {
NonConfigurationInstances nc =
(NonConfigurationInstances) getLastNonConfigurationInstance();
if (nc != null) {
// Restore the ViewModelStore from NonConfigurationInstances
mViewModelStore = nc.viewModelStore;
}
if (mViewModelStore == null) {
mViewModelStore = new ViewModelStore();
}
}
}

先通过 getLastNonConfigurationInstance() 获取 NonConfigurationInstances 实例,如果不为空,则 Activity 中的 ViewModelStore 实例就是 NonConfigurationInstances 中的 ViewModelStore 实例,否则就 new 一个新的 ViewModelStore。

NonConfigurationInstances 是 ComponentActivity 的静态内部类:

1
2
3
4
static final class NonConfigurationInstances {
Object custom;
ViewModelStore viewModelStore;
}

getLastNonConfigurationInstance() 方法是 android.app.Activity 提供的方法,可以用它来获取最近一次保存的”non-configuration instance data”。那么这个数据是在什么时候保存的呢?

是在系统调用 onRetainNonConfigurationInstance() 时保存的。如果 Activity 由于 configuration 更改而导致 Activity 销毁并立刻为新的configuration 重建时,我们可以通过此方法 return 我们想保存的任何对象,包括 Activity 自身的实例,后续可以在新的 Activity 实例中通过 getLastNonConfigurationInstance() 方法获取被保存的数据。

ComponentActivity 重写了onRetainNonConfigurationInstance() 方法,如果当前 Activity 有使用 ViewModel,那么 mViewModelStore 一定不为空(在 getViewModelStore() 时调用 ensureViewModelStore() 确保不为空),那么就将当前的 ViewModelStore 保存到 NonConfigurationInstances 中并 return。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public final Object onRetainNonConfigurationInstance() {
// Maintain backward compatibility.
Object custom = onRetainCustomNonConfigurationInstance();

ViewModelStore viewModelStore = mViewModelStore;
if (viewModelStore == null) {
// No one called getViewModelStore(), so see if there was an existing
// ViewModelStore from our last NonConfigurationInstance
NonConfigurationInstances nc =
(NonConfigurationInstances) getLastNonConfigurationInstance();
if (nc != null) {
viewModelStore = nc.viewModelStore;
}
}

if (viewModelStore == null && custom == null) {
return null;
}

NonConfigurationInstances nci = new NonConfigurationInstances();
nci.custom = custom;
nci.viewModelStore = viewModelStore;
return nci;
}

这样一来,在 ensureViewModelStore() 方法中通过 getLastNonConfigurationInstance() 获取到的就是上次 Activity 销毁时保存的 ViewModelStore 实例。

简而言之,就是通过 Activity 的 onRetainNonConfigurationInstance() 和 getLastNonConfigurationInstance() 实现数据保存和恢复。

那么 onRetainNonConfigurationInstance 在 Activity 销毁时将数据保存在哪里了呢?

跟踪 ActivityThread 中 performDestroyActivity 方法,最终保存在了 ActivityClientRecord 的 lastNonConfigurationInstances 中:

1
2
3
4
5
6
7
8
9
10
if (getNonConfigInstance) {
try {
r.lastNonConfigurationInstances = r.activity.retainNonConfigurationInstances();
} catch (Exception e) {
if (!mInstrumentation.onException(r.activity, e)) {
throw new RuntimeException("Unable to retain activity "
+ r.intent.getComponent().toShortString() + ": " + e.toString(), e);
}
}
}

也就是将数据保存在了 server 端。